package cn.edu.usst.cs.goldfish.booking.meetingroom.handler;

import cn.edu.usst.cs.goldfish.booking.meetingroom.mybatis.ExceptionMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingRequestValueException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.Arrays;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    private final ExceptionMapper exceptionMapper;

    public GlobalExceptionHandler(ExceptionMapper exceptionMapper) {
        this.exceptionMapper = exceptionMapper;
    }

    @ExceptionHandler(GoldfishBookingException.class)
    public ResponseEntity<String> handleException(GoldfishBookingException ex) {
        return ResponseEntity.badRequest().body(ex.getMessage());
    }

    @ExceptionHandler({MissingRequestValueException.class, ServletRequestBindingException.class})
    public ResponseEntity<String> handleMissingRequestValueException(Exception ex) {
        exceptionMapper.getTrace(ex);
        if (ex instanceof MissingRequestValueException missingRequestValueException) {
            return ResponseEntity.badRequest().body("缺少参数：" + missingRequestValueException.getBody());
        } else if (ex instanceof ServletRequestBindingException servletRequestBindingException) {
            Object[] args = servletRequestBindingException.getDetailMessageArguments();
            return ResponseEntity.badRequest().body("缺少参数" + Arrays.toString(args));
        } else {
            return ResponseEntity.badRequest().body(ex.getMessage());
        }
    }

    @ExceptionHandler(SQLException.class)
    public ResponseEntity<String> handleSQLException(SQLException ex) {
        exceptionMapper.getTrace(ex);
        return ResponseEntity.badRequest().body("数据错误，编号" + getId(ex));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGenericException(Exception ex) {
        Long id = getId(ex);
        return ResponseEntity.internalServerError().body("未知异常，编号：" + id);
    }

    @ExceptionHandler(GoldfishBookingAuthException.class)
    public ResponseEntity<String> handleAuthException(GoldfishBookingAuthException ex) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage());
    }

    private Long getId(Exception ex) {
        StringWriter sw = new StringWriter();
        ex.printStackTrace(new PrintWriter(sw));
        log.error("{} - An error occurred:\n {}", ex.getClass(), sw);
        Long id = exceptionMapper.minFreeId();
        exceptionMapper.save(id, sw.toString());
        return id;
    }
}